#include "ConsistentHash.h"

#include "loadbalancer.h"


extern std::map<std::thread::id, std::shared_ptr<std::mutex>> readLockMap_;

// 移除服务器
void ConsistentHash::removeNode(const BackendSession* servNode, int index)
{
    std::cout << "ConsistentHash removeNode------" << std::endl;
    for (int i = 0; i < virtualNodeNum_; ++i)
    {
        std::string addr = servNode->getBackendAddr() + std::to_string(i % 128);
        uint32_t hashValue;
        MurmurHash3_x86_32(addr.data(), addr.size(), 0, &hashValue);
        serverNodeMap_[index].erase(hashValue);
    }
    // --nodeNum_;
}
// 添加服务器
void ConsistentHash::addNode(BackendSession* servNode, int index)
{
    std::cout << "ConsistentHash addNode------" << std::endl;
    for (int i = 0; i < virtualNodeNum_; ++i)
    {
        std::string addr = servNode->getBackendAddr() + std::to_string(i % 128);
        uint32_t hashValue;
        MurmurHash3_x86_32(addr.data(), addr.size(), 0, &hashValue);
        std::cout << "MurmurHash3_x86_32 : " << hashValue << std::endl;
        serverNodeMap_[index].insert(std::pair<uint32_t, BackendSession*>(hashValue, servNode));
    }
    // ++nodeNum_;
}
//选择服务器
BackendSession* ConsistentHash::selectServer(const std::string clnt_addr)
{
    int index = index_.load(memory_order_acquire);
    std::string addr = clnt_addr;
    uint32_t hashValue;
    MurmurHash3_x86_32(addr.data(), addr.size(), 0, &hashValue);
    auto it = serverNodeMap_[index].lower_bound(hashValue);
    if (it == serverNodeMap_[index].end()) it = serverNodeMap_[index].begin();
    return it->second;
}

void ConsistentHash::modify(BackendSession* servNode, int flag) {
    std::lock_guard<std::mutex> lk(modify_mutex_);

    int bg_index = !index_.load(memory_order_relaxed);

    if (flag == 0) addNode(servNode, bg_index);
    else removeNode(servNode, bg_index);

    index_.store(bg_index, memory_order_release);
    bg_index = !bg_index;

    {
        for (auto lock : readLockMap_) {
            std::lock_guard<std::mutex> lk(*lock.second);
        }
    }

    if (flag == 0) addNode(servNode, bg_index);
    else removeNode(servNode, bg_index);
}